from dvadmin.utils.serializers import CustomModelSerializer
from dvadmin.utils.json_response import SuccessResponse, ErrorResponse, DetailResponse
from dvadmin.utils.viewset import CustomModelViewSet
from rest_framework.decorators import action
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
from urllib.parse import urljoin
import requests
import json
import re

from ops.devops.utils.util_config import get_config
from ops.devops.models import Cdn, Module, Ref
from ops.devops.utils import utils_cdn
from ops.chatbot.utils.send_msg import SendMessage
from ops.devops.serializers.CdnSerializers import CdnSerializer, RefSerializer


class CdnViewSet(CustomModelViewSet):
    """
    devops接口
    list:查询
    create:新增
    update:修改
    retrieve:单例
    destroy:删除
    """
    exclude_field = []
    queryset = Cdn.objects.all()
    serializer_class = CdnSerializer
    extra_filter_backends = []
    permission_classes = []
    search_fields = ['domain', 'status', 'business_type', 'origin_type', 'service_area', 'status']

    # 重写方法
    def create(self, request, *args, **kwargs):
        data = request.data

        # 获取参数
        domain = data.get('domain')
        ip_or_domain = data.get('ip_or_domain')
        business_type = data.get('business_type', 'web')
        service_area = data.get('service_area', 'mainland_china')
        origin_type = data.get('origin_type', 'ipaddr')
        domain_resolve = data.get('domain_resolve')

        try:
            conf = get_config('cloud')
            client = utils_cdn.CreateClient.create_client(conf.get('cloud_type'), conf.get('access_id'),
                                                          conf.get('access_secret'))
            res = utils_cdn.CdnOp.create_domain(client, domain, ip_or_domain, business_type, service_area, origin_type)

            # 创建域名，返回状态码不为200则直接return失败
            if res.get('code') != 200:
                return ErrorResponse(code=res.get('code'), msg="cdn域名添加失败，原因：{0}".format(res.get('res')))

            # 把cname存入库中
            data['cname'] = res.get('res').domain.cname

            # 更新域名信息
            res = utils_cdn.CdnOp.update_https_info(client, conf.get('cert_name'), domain)

            if res.get('code') != 200:
                return ErrorResponse(code=res.get('code'), msg="更新cdn域名失败，原因：{0}".format(res.get('res')))

            serializer = self.get_serializer(data=data, request=request)
            serializer.is_valid(raise_exception=True)
            self.perform_create(serializer)

            # 判断是否需要添加域名
            if domain_resolve:
                data = {
                    "domain": domain,
                    "type": "CNAME",
                    "ttl": "300",
                    "records": data['cname'],
                    "description": "add by devops from cdn"
                }
                headers = {
                    "Content-Type": "application/json;charset=UTF-8"
                }
                devops_addr = get_config('common').get('devops_addr')
                result = requests.post(urljoin(devops_addr, 'api/devops/domain_records/'), json=data, headers=headers)

                res = json.loads(result.text)
                if res.get('code') != 200:
                    return ErrorResponse(code=res.get('code'), msg="同步添加域名解析失败，原因：{0}".format(res.get('msg')))
            return DetailResponse(data=serializer.data, msg="cdn添加成功")
        except Exception as e:
            return ErrorResponse(code=400, msg="cdn域名添加失败，原因：{0}".format(e))

    # 从云获取domain并更新到数据库中
    @swagger_auto_schema(request_body=openapi.Schema(
        type=openapi.TYPE_OBJECT
    ), operation_summary='获取cdn记录')
    @action(methods=['PUT'], detail=False)
    def get_cdn(self, request, *args, **kwargs):
        conf = get_config('cloud')
        client = utils_cdn.CreateClient.create_client(conf.get('cloud_type'), conf.get('access_id'),
                                                      conf.get('access_secret'))

        domain_list = utils_cdn.CdnOp.list_domains(client)

        # 轮询查询结果，更新或者新增到记录表中
        for dt in domain_list:
            domain_name = dt.domain_name
            print(domain_name)

            try:
                print('cdn域名存在，更新表')
                cdn_tmp = Cdn.objects.get(domain=domain_name)

                cdn_tmp.status = dt.domain_status
                cdn_tmp.origin_type = dt.sources[0].origin_type
                cdn_tmp.ip_or_domain = dt.sources[0].ip_or_domain
                cdn_tmp.business_type = dt.business_type
                cdn_tmp.cname = dt.cname
                cdn_tmp.save()
            except Cdn.DoesNotExist:
                print('cdn域名不存在，新增cdn域名记录到表中')
                cdn_info = {
                    'domain': domain_name,
                    'status': dt.domain_status,
                    'origin_type': dt.sources[0].origin_type,
                    'ip_or_domain': dt.sources[0].ip_or_domain,
                    'business_type': dt.business_type,
                    'cname': dt.cname
                }
                obj = Cdn(**cdn_info)
                obj.save()
        return SuccessResponse(data="cdn信息获取成功")


class RefViewSet(CustomModelViewSet):
    """
    devops接口
    list:查询
    create:新增
    update:修改
    retrieve:单例
    destroy:删除
    """
    exclude_field = []
    queryset = Ref.objects.all()
    serializer_class = RefSerializer
    extra_filter_backends = []
    permission_classes = []
    search_fields = ['domain', 'status', 'business_type', 'origin_type', 'service_area', 'status']

    def create(self, request, *args, **kwargs):

        data = request.data
        domains_or_cnames = data.get('urls')
        conf = get_config('cloud')
        webhook = get_config('dd').get('webhook')

        client = utils_cdn.CreateClient.create_client(conf.get('cloud_type'), conf.get('access_id'),
                                                      conf.get('access_secret'))

        if not domains_or_cnames:
            return ErrorResponse(data="别名或域名列表为空，请检查！")

        for domain_or_cname in domains_or_cnames:
            # 正则判断输入的是域名还是别名，未匹配到则默认为别名
            pattern = re.compile(r'(http|https)://.*/')
            m = pattern.match(domain_or_cname)

            # 输入为别名时流程
            if not m:
                project_info = domain_or_cname.split('-')
                # 判断，默认env为pre
                if len(project_info) > 1:
                    alias_name, env = project_info[0:2]
                else:
                    alias_name, env = project_info[0], 'pre'
                try:
                    params = Module.objects.get(alias_name=alias_name).params
                    domain = json.loads(params).get(env).get('domain')
                except Module.DoesNotExist:
                    SendMessage.send_md(webhook, '别名{0}不存在，请检查！'.format(alias_name))
                    domain = ''
            else:
                domain = domain_or_cname

            # 域名存在则执行刷新动作
            if domain:
                res = utils_cdn.CdnOp.refresh_dcdn(client, domain, conf.get('type', 'directory'))
                status = 'success'
                if res.get('code') != 200:

                    SendMessage.send_text(webhook, 'cdn刷新失败，原因：{0}'.format(res.get('msg')))
                    status = 'failed'

                data['url'] = domain
                data['status'] = status
                data['operator'] = request.user.username
                serializer = self.get_serializer(data=data)
                serializer.is_valid(raise_exception=True)
                self.perform_create(serializer)

        return SuccessResponse(data="缓存刷新操作完成")
